import edu.udo.cs.wvtool.main.WVTWordVector;

/*************************************************************************
 *  Compilation:  javac Vector.java
 *  Execution:    java Vector
 *
 *  Implementation of a vector of real numbers.
 *
 *  This class is implemented to be immutable: once the client program
 *  initialize a Vector, it cannot change any of its fields
 *  (N or data[i]) either directly or indirectly. Immutability is a
 *  very desirable feature of a data type.
 *
 *
 *  % java Vector
 *  x        =  (1.0, 2.0, 3.0, 4.0)
 *  y        =  (5.0, 2.0, 4.0, 1.0)
 *  x + y    =  (6.0, 4.0, 7.0, 5.0)
 *  10x      =  (10.0, 20.0, 30.0, 40.0)
 *  |x|      =  5.477225575051661
 *  <x, y>   =  25.0
 *  |x - y|  =  5.0990195135927845
 *
 *  Note that java.util.Vector is an unrelated Java library class.
 *
 *************************************************************************/

public class WVector  {

    private final int N;         // length of the vector
    private double[] values;       // array of vector's components
    private int label;

    // create the zero vector of length N
    public WVector(WVTWordVector wv) {
        this.N = wv.getValues().length;
        this.values = wv.getValues();
        this.label = wv.getDocumentInfo().getClassValue();
    }

    public WVector(int N) {
        this.N = N;
        this.values = new double[N];
    }

    // create a vector from an array
    public WVector(double[] data) {
        N = data.length;

        // defensive copy so that client can't alter our copy of data[]
        this.values = new double[N];

        for (int i = 0; i < N; i++)
            this.values[i] = data[i];
    }

    // create a vector from either an array or a vararg list
    // this constructor uses Java's vararg syntax to support
    // a constructor that takes a variable number of arguments, such as
    // Vector x = new Vector(1.0, 2.0, 3.0, 4.0);
    // Vector y = new Vector(5.0, 2.0, 4.0, 1.0);
/*
    public Vector(double... data) {
        N = data.length;

        // defensive copy so that client can't alter our copy of data[]
        this.data = new double[N];
        for (int i = 0; i < N; i++)
            this.data[i] = data[i];
    }
*/
    // return the length of the vector
    public int length() {
        return N;
    }

    // return the inner product of this Vector a and b
    public double dot(WVector that) {
        if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
        double sum = 0.0;
        for (int i = 0; i < N; i++)
            sum = sum + (this.values[i] * that.values[i]);
        return sum;
    }

    // return the Euclidean norm of this Vector
    public double magnitude() {
        return Math.sqrt(this.dot(this));
    }

    // return the Euclidean distance between this and that
    public double distanceTo(WVector that) {
        if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
        return this.minus(that).magnitude();
    }

    // return this + that
    public WVector plus(WVector that) {
        if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
        WVector c = new WVector(N);
        for (int i = 0; i < N; i++)
            c.values[i] = this.values[i] + that.values[i];
        return c;
    }

    // return this - that
    public WVector minus(WVector that) {
        if (this.N != that.N) throw new RuntimeException("Dimensions don't agree");
        WVector c = new WVector(N);
        for (int i = 0; i < N; i++)
            c.values[i] = this.values[i] - that.values[i];
        return c;
    }

    // return the corresponding coordinate
    public double cartesian(int i) {
        return values[i];
    }

    // create and return a new object whose value is (this * factor)
    public WVector times(double factor) {
        WVector c = new WVector(N);
        for (int i = 0; i < N; i++)
            c.values[i] = factor * values[i];
        return c;
    }


    // return the corresponding unit vector
    public WVector direction() {
        if (this.magnitude() == 0.0) throw new RuntimeException("Zero-vector has no direction");
        return this.times(1.0 / this.magnitude());
    }

    // return a string representation of the vector
    public String toString() {
        String s = "(";
        for (int i = 0; i < N; i++) {
            s += values[i];
            if (i < N-1) s+= ", "; 
        }
        return s + ")";
    }

    public double[] getValues() {
        return values;
    }

    public int getLabel() {
        return label;
    }
    public void setLabel(int n) {
        this.label = n;
    }

}
